package com.example.artemis.statistics;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 默认统计服务实现
 * 基于事件监听器模式的统计服务
 */
public class DefaultStatisticsService implements StatisticsService {

    private static final Logger logger = LoggerFactory.getLogger(DefaultStatisticsService.class);

    // 统计数据仓库
    private final StatisticsRepository repository;

    // 定时清理任务
    private final ScheduledExecutorService cleanupExecutor;

    // 服务状态
    private final AtomicBoolean running = new AtomicBoolean(false);

    // 时间窗口管理配置
    private static final int DEFAULT_CLEANUP_INTERVAL_MINUTES = 5;
    private static final int MAX_TIME_WINDOWS = 100;

    public DefaultStatisticsService() {
        this.repository = new StatisticsRepository();
        this.cleanupExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread thread = new Thread(r, "StatisticsService-Cleanup");
            thread.setDaemon(true);
            return thread;
        });
    }

    // ================== 统计获取方法 ==================

    @Override
    public MessageStatistics getGlobalStatistics() {
        return repository.getGlobalStatistics();
    }

    @Override
    public QueueStatistics getQueueStatistics(String queueName) {
        return repository.getQueueStatistics(queueName);
    }

    @Override
    public Map<String, QueueStatistics> getAllQueueStatistics() {
        return repository.getAllQueueStatistics();
    }

    @Override
    public TimeWindowStatistics getTimeWindowStatistics(LocalDateTime windowStart, long windowSizeMinutes) {
        String windowKey = StatisticsRepository.generateTimeWindowKey(windowStart, windowSizeMinutes);
        return repository.getTimeWindowStatistics(windowKey);
    }

    @Override
    public List<TimeWindowStatistics> getRecentTimeWindowStatistics(int windowCount, long windowSizeMinutes) {
        List<TimeWindowStatistics> result = new ArrayList<>();
        LocalDateTime currentTime = LocalDateTime.now();

        for (int i = 0; i < windowCount; i++) {
            LocalDateTime windowStart = currentTime.minus((i + 1) * windowSizeMinutes, ChronoUnit.MINUTES);
            String windowKey = StatisticsRepository.generateTimeWindowKey(windowStart, windowSizeMinutes);
            TimeWindowStatistics statistics = repository.getTimeWindowStatistics(windowKey);
            if (statistics != null) {
                result.add(statistics);
            }
        }

        return result;
    }

    // ================== 事件记录方法 ==================

    @Override
    public void recordMessageSent(String messageId, String queueName, String producerId,
                                 long productionTime, int messageSize) {
        if (!running.get()) {
            return;
        }

        try {
            // 更新全局统计
            MessageStatistics globalStats = repository.getGlobalStatistics();
            globalStats.incrementSent(1);
            globalStats.addProductionTime(productionTime);

            // 更新队列统计
            QueueStatistics queueStats = repository.getOrCreateQueueStatistics(queueName);
            queueStats.incrementSent();
            queueStats.addProductionTime(productionTime);

            // 更新时间窗口统计
            updateTimeWindowStatistics(queueName, "SENT", productionTime);

            logger.debug("记录消息发送: messageId={}, queueName={}, producerId={}, time={}ms",
                    messageId, queueName, producerId, productionTime);

        } catch (Exception e) {
            logger.error("记录消息发送统计时发生错误", e);
        }
    }

    @Override
    public void recordMessageProcessed(String messageId, String queueName, String consumerId,
                                     long processingTime, int deliveryAttempt, long messageAge) {
        if (!running.get()) {
            return;
        }

        try {
            // 更新全局统计
            MessageStatistics globalStats = repository.getGlobalStatistics();
            globalStats.incrementProcessed(1);
            globalStats.addProcessingTime(processingTime);

            // 更新队列统计
            QueueStatistics queueStats = repository.getOrCreateQueueStatistics(queueName);
            queueStats.incrementProcessed();
            queueStats.incrementConsumerActivity(consumerId);
            queueStats.addProcessingTime(processingTime);

            // 更新时间窗口统计
            updateTimeWindowStatistics(queueName, "PROCESSED", processingTime);

            logger.debug("记录消息处理: messageId={}, queueName={}, consumerId={}, time={}ms, attempt={}",
                    messageId, queueName, consumerId, processingTime, deliveryAttempt);

        } catch (Exception e) {
            logger.error("记录消息处理统计时发生错误", e);
        }
    }

    @Override
    public void recordMessageFailed(String messageId, String queueName, String consumerId,
                                   long processingTime, int deliveryAttempt,
                                   String errorMessage, String failureType, boolean willRetry) {
        if (!running.get()) {
            return;
        }

        try {
            // 更新全局统计
            MessageStatistics globalStats = repository.getGlobalStatistics();
            globalStats.incrementFailed(1);
            globalStats.addProcessingTime(processingTime);

            // 更新队列统计
            QueueStatistics queueStats = repository.getOrCreateQueueStatistics(queueName);
            queueStats.incrementFailed();
            queueStats.incrementConsumerActivity(consumerId);
            queueStats.addProcessingTime(processingTime);

            // 如果会重试，增加重试计数
            if (willRetry) {
                globalStats.incrementRetried(1);
                queueStats.incrementRetried();
            }

            // 更新时间窗口统计
            updateTimeWindowStatistics(queueName, "FAILED", processingTime);

            logger.debug("记录消息失败: messageId={}, queueName={}, consumerId={}, error={}, willRetry={}",
                    messageId, queueName, consumerId, failureType, willRetry);

        } catch (Exception e) {
            logger.error("记录消息失败统计时发生错误", e);
        }
    }

    // ================== 统计管理方法 ==================

    @Override
    public void resetAllStatistics() {
        logger.info("重置所有统计数据");
        repository.resetAll();
    }

    @Override
    public void resetQueueStatistics(String queueName) {
        logger.info("重置队列统计数据: {}", queueName);
        QueueStatistics queueStats = repository.getQueueStatistics(queueName);
        if (queueStats != null) {
            queueStats.reset();
        }
    }

    @Override
    public void cleanupExpiredStatistics() {
        logger.debug("清理过期统计数据");
        repository.cleanupExpiredTimeWindows();
    }

    // ================== 生命周期管理 ==================

    @Override
    public void start() {
        if (running.compareAndSet(false, true)) {
            logger.info("启动统计服务");

            // 启动定时清理任务
            cleanupExecutor.scheduleAtFixedRate(
                    this::cleanupExpiredStatistics,
                    DEFAULT_CLEANUP_INTERVAL_MINUTES,
                    DEFAULT_CLEANUP_INTERVAL_MINUTES,
                    TimeUnit.MINUTES
            );

            logger.info("统计服务已启动，定时清理间隔: {} 分钟", DEFAULT_CLEANUP_INTERVAL_MINUTES);
        }
    }

    @Override
    public void stop() {
        if (running.compareAndSet(true, false)) {
            logger.info("停止统计服务");

            // 停止清理任务
            cleanupExecutor.shutdown();
            try {
                if (!cleanupExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                    cleanupExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                cleanupExecutor.shutdownNow();
            }

            logger.info("统计服务已停止");
        }
    }

    @Override
    public boolean isRunning() {
        return running.get();
    }

    // ================== 报告生成 ==================

    @Override
    public String getStatisticsSummary() {
        StringBuilder summary = new StringBuilder();
        summary.append("=== 统计服务摘要 ===\n");
        summary.append(String.format("服务状态: %s\n", running.get() ? "运行中" : "已停止"));
        summary.append(repository.getSummary());
        summary.append("==================\n");
        return summary.toString();
    }

    @Override
    public String getDetailedReport() {
        StringBuilder report = new StringBuilder();
        report.append("=== 详细统计报告 ===\n");
        report.append(String.format("报告生成时间: %s\n", LocalDateTime.now()));
        report.append(String.format("服务状态: %s\n", running.get() ? "运行中" : "已停止"));

        // 全局统计
        report.append("\n");
        report.append(repository.getGlobalStatistics().getDetailedReport());

        // 队列统计
        Map<String, QueueStatistics> queueStats = getAllQueueStatistics();
        if (!queueStats.isEmpty()) {
            report.append("\n队列详细统计:\n");
            queueStats.values().forEach(stats -> {
                report.append(stats.getDetailedReport());
                report.append("\n");
            });
        }

        // 时间窗口统计（最近几个窗口）
        List<TimeWindowStatistics> recentWindows = getRecentTimeWindowStatistics(3, 5);
        if (!recentWindows.isEmpty()) {
            report.append("最近时间窗口统计:\n");
            recentWindows.forEach(window -> {
                report.append(window.getDetailedReport());
                report.append("\n");
            });
        }

        report.append("====================\n");
        return report.toString();
    }

    // ================== 私有辅助方法 ==================

    /**
     * 更新时间窗口统计
     */
    private void updateTimeWindowStatistics(String queueName, String eventType, long time) {
        try {
            LocalDateTime now = LocalDateTime.now();
            long windowSizeMinutes = 5; // 5分钟窗口

            // 计算窗口开始时间（向下取整到最近的5分钟边界）
            LocalDateTime windowStart = now.minusMinutes(now.getMinute() % windowSizeMinutes)
                    .withSecond(0)
                    .withNano(0);

            String windowKey = StatisticsRepository.generateTimeWindowKey(windowStart, windowSizeMinutes);
            TimeWindowStatistics windowStats = repository.getOrCreateTimeWindowStatistics(
                    windowKey, windowStart, windowSizeMinutes);

            // 更新窗口统计
            windowStats.incrementMessageCount();

            switch (eventType) {
                case "SENT":
                    // 发送事件不直接影响处理统计，但记录消息数
                    break;
                case "PROCESSED":
                    windowStats.incrementSuccessCount();
                    windowStats.addProcessingTime(time);
                    break;
                case "FAILED":
                    windowStats.incrementFailureCount();
                    windowStats.addProcessingTime(time);
                    break;
                default:
                    logger.warn("未知的事件类型: {}", eventType);
            }

            // 限制时间窗口数量，避免内存泄漏
            limitTimeWindowCount();

        } catch (Exception e) {
            logger.error("更新时间窗口统计时发生错误", e);
        }
    }

    /**
     * 限制时间窗口数量，防止内存泄漏
     */
    private void limitTimeWindowCount() {
        Map<String, TimeWindowStatistics> allWindows = repository.getAllTimeWindowStatistics();
        if (allWindows.size() > MAX_TIME_WINDOWS) {
            // 按时间排序，移除最旧的窗口
            List<Map.Entry<String, TimeWindowStatistics>> sortedWindows = new ArrayList<>(allWindows.entrySet());
            sortedWindows.sort(Comparator.comparing(entry -> entry.getValue().getWindowStart()));

            int toRemove = sortedWindows.size() - MAX_TIME_WINDOWS;
            for (int i = 0; i < toRemove; i++) {
                String keyToRemove = sortedWindows.get(i).getKey();
                repository.removeTimeWindowStatistics(keyToRemove);
                logger.debug("移除旧的时间窗口统计: {}", keyToRemove);
            }
        }
    }
}